<?php
/**
 * Created by PhpStorm.
 * User: wiggin
 * Date: 2017/11/18
 */

namespace App\Utility\Logis;

abstract class LogisApiAbstract
{
    protected $isDebug = false;             //debug (暂未开发)

    protected $httpHandle = null;           //网络请求对象
    protected $sendType = 'curl';           //curl || webservice
    protected $sendMethod = 'post';         //设置请求方法 curl为此类方法(post || get || put || delete) webservice为调用的方法名

    protected $apiUrl = '';                 //本次API请求的url

    protected $requestHeader = array();     //请求头
    protected $requestBody = null;          //请求参数

    protected $response = array();          //请求的结果 array('status'=>false, 'errorMsg'=>'') OR array('status'=>true, 'data'=>'')

    protected $selfError = false;           //自身class的程序错误
    protected $selfErrorMsg = '';           //自身class的程序错误message

    protected $type = null;                 //设置本次请求的type

    protected $soapClient = null;           //webservice 客服端实例
//    protected $soapFunctions = array();     //webservice 方法的列表

    protected $httpConfig = array(          //curl参数设置  可以通过重新覆盖
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_AUTOREFERER => true,
        CURLOPT_CONNECTTIMEOUT => 60,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:5.0) Gecko/20110619 Firefox/5.0'
    );

    protected $webServiceCfg = array('encoding' => 'UTF-8');     //webservice参数 可以通过重新覆盖

    protected function init()
    {
        try {
            if ($this->sendType == 'curl') {
                $this->initCurl();
            } elseif ($this->sendType == 'webservice') {
                $this->initWebService();
            }
        } catch (\Exception $e) {
            $this->selfError = true;
            $this->selfErrorMsg = 'initException:' . $e->getMessage();
        }
    }

    /**
     * 设置参数
     * @param $name
     * @param $arguments
     */
    public function __call($name, $arguments)
    {
        $this->selfError = true;
        $this->selfErrorMsg = '调用未定义的方法：' . $name;
        return $this;
    }

    /**
     * @param $name
     */
    public function __get($name)
    {
        $this->selfError = true;
        $this->selfErrorMsg = '调用未定义的属性：' . $name;
        return $this;
    }

    /**
     * @param $type
     * @return $this
     */
    public function setType($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * 设置每个接口的自有参数
     * @param $config
     * @return bool
     */
    public function setApiConfig($config)
    {
        if (!is_array($config)) {
            return false;
        }
        foreach ($config as $key => $val) {
            $this->$key = $val;
        }
    }

    /**
     * 设置本次请求的url
     * @param $url
     */
    public function setApiUrl($url)
    {
        $this->apiUrl = $url;
        return $this;
    }

    /**
     * 设置请求头
     * @param $header
     */
    public function setRequestHeader($header)
    {
        $this->requestHeader = $header;
        return $this;
    }

    /**
     * 设置请求body
     */
    public function setRequestBody($requestBody)
    {
        $this->requestBody = $requestBody;
        return $this;
    }

    /**
     * @param $method
     * @return $this
     */
    public function setSendMethod($method)
    {
        $this->sendMethod = $method;
        return $this;
    }

    /**
     * @param $type
     * @return $this
     */
    public function setSendType($type)
    {
        $this->sendType = $type;
        return $this;
    }

    /**
     * 获取结果
     * @return array|null
     */
    public function getResponse()
    {
        if ($this->selfError) {
            $this->response = array(
                'status' => false,
                'errorMsg' => $this->selfErrorMsg
            );
        }
        //初始化结果
        $this->selfError = false;
        $this->selfErrorMsg = '';
        $response = $this->response;
        $this->response = array();
        return $response;
    }

    /**
     * 发送请求
     */
    public function sendRequest()
    {
        if (!$this->selfError) {      //发送请求前如果本身有异常 直接不发送请求
            $this->sendRequestByType();
        }
        return $this;
    }

    /**
     * 解析结果
     */
    abstract protected function parseResponseByType($response);

    /**
     * 生成请求参数
     */
    abstract protected function createRequestByType();

    /**
     * 设置发送请求前处理方法
     */
    protected function sendRequestBefore()
    {
        return true;
    }

    /**
     * 发送请求的私有方法
     */
    private function sendRequestByType()
    {
        $this->sendRequestBefore();
        $response = '';
        $this->createRequestByType();
        if (!empty($this->sendType) || !empty($this->sendMethod)) {
            if ($this->sendType == 'curl') {
                $method = 'curl' . ucfirst($this->sendMethod);
                if (method_exists($this, $method)) {
                    if (empty($this->httpHandle)) {
                        $this->initCurl();
                    }
                    $result = $this->{$method}($this->apiUrl, $this->requestBody, $this->requestHeader);
                } else {
                    $this->selfError = true;
                    $this->selfErrorMsg = '接口文件设置的请求方式curl对应的请求方法"' . $this->sendMethod . '"不支持';
                }
                if (isset($result)) {
                    if ($result['status']) {
                        $response = $result['data'];
                    } else {
                        $this->selfError = true;
                        $this->selfErrorMsg = $result['errorMsg'];
                    }
                }
            } elseif ($this->sendType == 'webservice') {
                try {
                    if (empty($this->soapClient)) {
                        $this->initWebService();
                    }
                    $response = $this->soapClient->__soapCall($this->sendMethod, $this->requestBody);
                } catch (\Exception $e) {
                    $this->selfError = true;
                    $this->selfErrorMsg = 'Exception:' . $e->getMessage();
                }
            } else {
                $this->selfError = true;
                $this->selfErrorMsg = '接口文件设置的请求方式不正确';
            }
        } else {
            $this->selfError = true;
            $this->selfErrorMsg = '接口文件设置的请求方式或者请求方法为空';
        }
        if (!$this->selfError) {
            $this->response = $this->parseResponseByType($response);
        }
        return $this;
    }

    /**
     * get
     * @param $url
     * @return mixed
     */
    private function curlGet($url, $requestData = array(), $header = array())
    {
        $return = array(
            'status' => false,
            'errorMsg' => 'curl请求异常'
        );
        try {
            $myHeader = array();
            $this->customMergeArray($myHeader, $header);
            $requestData = !empty($requestData) ? http_build_query($requestData) : '';
            $url .= !empty($requestData) ? ('?' . $requestData) : '';
            curl_setopt($this->httpHandle, CURLOPT_URL, $url);
            curl_setopt($this->httpHandle, CURLOPT_HTTPGET, true);
            if (!empty($myHeader)) {
                curl_setopt($this->httpHandle, CURLOPT_HTTPHEADER, $myHeader);
            }
            $result = curl_exec($this->httpHandle);
            $error = curl_error($this->httpHandle);
            if (!empty($error)) {
                $return['errorMsg'] = $error;
            } else {
                unset($return['errorMsg']);
                $return['status'] = true;
                $return['data'] = $result;
            }
        } catch (\Exception $e) {
            $return['errorMsg'] = 'CURL_Exception:' . $e->getMessage();
        }
        return $return;
    }

    /**
     * post
     * @param $url
     * @param $postData
     * @param array $header
     * @param array $config
     * @return mixed
     */
    private function curlPost($url, $postData, $header = array())
    {
        $return = array(
            'status' => false,
            'errorMsg' => 'curl请求异常'
        );
        try {
            $myHeader = array();
            $this->customMergeArray($myHeader, $header);
            if (!empty($myHeader)) {
                curl_setopt($this->httpHandle, CURLOPT_HTTPHEADER, $myHeader);
            }
            curl_setopt($this->httpHandle, CURLOPT_URL, $url);
            curl_setopt($this->httpHandle, CURLOPT_POST, true);
            curl_setopt($this->httpHandle, CURLOPT_POSTFIELDS, $postData);
            $result = curl_exec($this->httpHandle);
            $error = curl_error($this->httpHandle);
            if (!empty($error)) {
                $return['errorMsg'] = $error;
            } else {
                unset($return['errorMsg']);
                $return['status'] = true;
                $return['data'] = $result;
            }
        } catch (\Exception $e) {
            $return['errorMsg'] = 'CURL_Exception:' . $e->getMessage();
        }
        return $return;
    }

    /**
     * 自定义数据合并
     * @param $array1
     * @param $array2
     */
    protected function customMergeArray(&$array1, $array2)
    {
        if (is_array($array2)) {
            foreach ($array2 as $key => $val) {
                if (is_array($val) && isset($array1[$key]) && is_array($array1[$key])) {
                    $this->customMergeArray($array1[$key], $val);
                } else {
                    $array1[$key] = $val;
                }
            }
        }
    }

    /**
     * 初始化curl
     */
    private function initCurl()
    {
        if (empty($this->httpHandle)) {
            $this->httpHandle = curl_init();
        }
        curl_setopt_array($this->httpHandle, $this->httpConfig);
    }

    /**
     * 初始化webservice
     */
    private function initWebService()
    {
        if (empty($this->soapClient)) {
            $this->soapClient = new \SoapClient($this->apiUrl, $this->webServiceCfg);
//            $this->soapFunctions = $this->soapClient->__getFunctions();
        }
    }

    /**
     * 释放资源
     */
    public function __destruct()
    {
        if (!empty($this->httpHandle)) {
            if ($this->sendType == 'curl') {
                curl_close($this->httpHandle);
            }
        }
        unset($this->httpHandle);
    }
}